// manages bitmap tiles with semantice meaning in the game

#include "tileManager.h"
#include <string.h>
#include <map>

//--- TYPES ---//
class Tile {
private:
	TILE_TYPE type;
	char *filename;
	Bitmap *bmp;
	Png *png;
	int width;
	int height;

public:
	Tile()
		: bmp(NULL), png(NULL) {}

	Tile(TILE_TYPE in_type, char *in_filename)
		: type(in_type), filename(in_filename)
	{
		char temp[32];
		strcpy(temp, in_filename);
		if ((type >= FLOOR) && (type <= EXIT))
		{
			bmp = new Bitmap(strcat(temp, ".bmp"));
			width = bmp->width;
			height = bmp->height;
		}
		else
		{
			png = new Png(strcat(temp, ".png"));
			width = (int)(png->width);
			height = (int)(png->height);
		}
	}

	~Tile() {
		// pcd: disabled to avoid crash at the end
//		delete bmp;
	}

	Bitmap *getBitmap() {
		return bmp;
	}

	Png *getPng()
	{
		return png;
	}

	int getWidth()
	{
		return width;
	}

	int getHeight()
	{
		return height;
	}
};

struct TilePair {
	TILE_TYPE type;
	char *filename;

	TilePair(TILE_TYPE in_type, char *in_filename)
		: type(in_type), filename(in_filename) {}
};

TilePair allTilePairs[] = {
	TilePair(FLOOR,    "assets/tiles/sand"),
	TilePair(WATER,    "assets/tiles/water"),
	TilePair(IN_FLOOR, "assets/tiles/in_floor"),
	TilePair(WALL,     "assets/tiles/wall"),
	TilePair(EXIT,     "assets/tiles/stairs"),

	TilePair(ILL_N, "assets/tiles/hero_back"),
	TilePair(ILL_S, "assets/tiles/hero_front"),
	TilePair(ILL_E, "assets/tiles/hero_right"),
	TilePair(ILL_W, "assets/tiles/hero_left"),

	TilePair(DOG_N, "assets/tiles/dog_back"),
	TilePair(DOG_S, "assets/tiles/dog_front"),
	TilePair(DOG_E, "assets/tiles/dog_right"),
	TilePair(DOG_W, "assets/tiles/dog_left"),

	TilePair(GUARD_N, "assets/tiles/g1_back"),
	TilePair(GUARD_S, "assets/tiles/g1_front"),
	TilePair(GUARD_E, "assets/tiles/g1_right"),
	TilePair(GUARD_W, "assets/tiles/g1_left"),

	TilePair(SG_N, "assets/tiles/command_back"),
	TilePair(SG_S, "assets/tiles/command_front"),
	TilePair(SG_E, "assets/tiles/command_right"),
	TilePair(SG_W, "assets/tiles/command_left"),

	TilePair(FAKE_DOG_N, "assets/tiles/dogfake_back"),
	TilePair(FAKE_DOG_S, "assets/tiles/dogfake_front"),
	TilePair(FAKE_DOG_E, "assets/tiles/dogfake_right"),
	TilePair(FAKE_DOG_W, "assets/tiles/dogfake_left"),

	TilePair(FAKE_GUARD_N, "assets/tiles/g1fake_back"),
	TilePair(FAKE_GUARD_S, "assets/tiles/g1fake_front"),
	TilePair(FAKE_GUARD_E, "assets/tiles/g1fake_right"),
	TilePair(FAKE_GUARD_W, "assets/tiles/g1fake_left"),

	TilePair(FAKE_SG_N, "assets/tiles/commandfake_back"),
	TilePair(FAKE_SG_S, "assets/tiles/commandfake_front"),
	TilePair(FAKE_SG_E, "assets/tiles/commandfake_right"),
	TilePair(FAKE_SG_W, "assets/tiles/commandfake_left"),

	TilePair(FOOD,      "assets/tiles/pizza"),
	TilePair(DEAD_BODY, "assets/tiles/bones"),

	TilePair(CLOAK_N,     "assets/tiles/cloak_back"),
	TilePair(CLOAK_S,     "assets/tiles/cloak_front"),
	TilePair(CLOAK_E,     "assets/tiles/cloak_right"),
	TilePair(CLOAK_W,     "assets/tiles/cloak_left"),
};

static char *titleScreenFilename  = "assets/screens/title.bmp";
static char *endingScreenFilename = "assets/screens/ending.bmp";
static char *cutSceneRoot = "assets/screens/cutscene";
static char *pauseScreenFilename = "assets/screens/pause.png";
static char *gameOverScreenFilename = "assets/screens/gameover.bmp";


//--- GLOBALs ---//
Tile allTiles[NUM_TILE_TYPES];
Bitmap *titleScreen = NULL;
map<string, Bitmap> cutSceneScreen;
Png *pauseScreen = NULL;
Bitmap *gameOverScreen = NULL;
Bitmap *endingScreen = NULL;

//--- FUNCTIONS ---//

// return true if curr is in [min, max]
static
bool boundsCheck(TILE_TYPE curr, TILE_TYPE min, TILE_TYPE max) {
	return curr >= min && curr <= max;
}

void initTiles() {
	int n = sizeof(allTilePairs) / sizeof(TilePair);
	for (int i = 0; i < n; i++) {
		TILE_TYPE type = allTilePairs[i].type;
		allTiles[type] = Tile(type, allTilePairs[i].filename);
	}

	titleScreen  = new Bitmap(titleScreenFilename);
	pauseScreen = new Png(pauseScreenFilename);
	gameOverScreen = new Bitmap(gameOverScreenFilename);
	endingScreen = new Bitmap(endingScreenFilename);
}

// returns the given tile
Bitmap *getTileBmp(TILE_TYPE tile) {
	assert(boundsCheck(tile, FLOOR, EXIT) ||	// check if it's a floor tile
		   boundsCheck(tile, ILL_N, FAKE_SG_W) ||	// check if it's an actor
		   boundsCheck(tile, FOOD, CLOAK_W));	// check if it's a power

	return allTiles[tile].getBitmap();
}

Png *getTilePng(TILE_TYPE tile) {
	assert(boundsCheck(tile, FLOOR, EXIT) ||	// check if it's a floor tile
		   boundsCheck(tile, ILL_N, FAKE_SG_W) ||	// check if it's an actor
		   boundsCheck(tile, FOOD, CLOAK_W));	// check if it's a power

	return allTiles[tile].getPng();
}

Bitmap *getTitleScreen() {
	return titleScreen;
}

Bitmap *getEndingScreen() {
	return endingScreen;
}

const char *getCutSceneRoot()
{
	return cutSceneRoot;
}

Bitmap *createCutScene(string levelFileType)
{
	if (cutSceneScreen.count(levelFileType) == 0)
	{
		cutSceneScreen.insert(pair<string, Bitmap>(levelFileType, Bitmap(string(string(cutSceneRoot) + levelFileType).data())));
	}
	if (cutSceneScreen.size() > 2)
	{
		map<string, Bitmap>::iterator mFirst = cutSceneScreen.begin();
		cutSceneScreen.erase(mFirst);
	}

	return &cutSceneScreen[levelFileType];
}

void clearCutScenes()
{
	cutSceneScreen.clear();
}

Png *getPauseScreen()
{
	return pauseScreen;
}

Bitmap *getGameOverScreen()
{
	return gameOverScreen;
}

// end of tileManager.cpp
